package com.demo.reduction;

import com.demo.common.Dish;
import com.demo.common.DishUtil;

import java.util.*;

import static java.util.stream.Collectors.*;

public class TestGroupingBy {
    public static void main(String[] args) {
        List<Dish> menu = DishUtil.getDishes();
        Map<Dish.Type, List<Dish>> dishesByType =
                            menu.stream().collect(groupingBy(Dish::getType));
        System.out.println(dishesByType);

        Map<CaloricLevel, List<Dish>> dishesByCaloricLevel =
                           menu.stream().collect(groupingBy(dish -> {
                               if(dish.getCalories() <= 400)
                                   return CaloricLevel.DIET;
                               else if(dish.getCalories() <= 700)
                                   return CaloricLevel.NORMAL;
                               else
                                   return CaloricLevel.FAT;
                           }));
        System.out.println(dishesByCaloricLevel);

        Map<Dish.Type, Map<CaloricLevel, List<Dish>>> dishesByTypeCaloricLevel =
                          menu.stream().collect(groupingBy(Dish::getType, groupingBy(
                                  dish -> {
                                      if(dish.getCalories() <= 400)
                                          return CaloricLevel.DIET;
                                      else if(dish.getCalories() <= 700)
                                          return CaloricLevel.NORMAL;
                                      else
                                          return CaloricLevel.FAT;
                                  }
                          )));
        System.out.println(dishesByTypeCaloricLevel);

        Map<Dish.Type, Long> typesCount = menu.stream()
                                              .collect(groupingBy(Dish::getType, counting()));
        System.out.println(typesCount);

        Map<Dish.Type, Optional<Dish>> mostCaloricByType =
                       menu.stream()
                           .collect(groupingBy(Dish::getType, maxBy(Comparator.comparingInt(Dish::getCalories))));
        System.out.println(mostCaloricByType);

        Map<Dish.Type, Dish> mostCaloricByType1 =
                menu.stream()
                    .collect(groupingBy(Dish::getType, collectingAndThen(
                            maxBy(Comparator.comparingInt(Dish::getCalories)), Optional::get
                    )));
        System.out.println(mostCaloricByType1);

        Map<Dish.Type, Integer> totalCaloricByType =
                menu.stream()
                    .collect(groupingBy(Dish::getType, summingInt(Dish::getCalories)));
        System.out.println(totalCaloricByType);

        Map<Dish.Type, Set<CaloricLevel>> caloricLevelsByType =
                menu.stream()
                    .collect(groupingBy(Dish::getType, mapping(
                            dish -> {
                                if(dish.getCalories() <= 400)
                                    return CaloricLevel.DIET;
                                else if(dish.getCalories() <= 700)
                                    return CaloricLevel.NORMAL;
                                else
                                    return CaloricLevel.FAT;
                            }, toSet()
                    )));
        System.out.println(caloricLevelsByType);
    }

    public enum CaloricLevel {DIET, NORMAL, FAT}
}
